﻿using Audit.Core;
using Audit.WebApi;
using DataCenter.Client;
using K9Nano.AspNetCore.Audit;
using K9Nano.Remoting;
using K9Nano.Runtime;
using K9Nano.Share.Exceptions;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace K9Cloud.Admin
{
    public class RemoteAuditDataProvider : WebApiAuditDataProvider
    {
        private readonly DataCenterClient _client;
        private readonly ILogger _logger;

        public RemoteAuditDataProvider(IHttpContextAccessor httpContextAccessor, DataCenterClient client, ILogger<RemoteAuditDataProvider> logger) : base(httpContextAccessor)
        {
            _client = client;
            _logger = logger;
        }

        protected virtual AuditMessage MapToMessage(AuditEvent auditEvent)
        {
            if (auditEvent is AuditEventWebApi apiEvent)
            {
                var session = HttpContextAccessor.HttpContext.RequestServices.GetRequiredService<ISessionContext>();
                var systemClock = HttpContextAccessor.HttpContext.RequestServices.GetService<K9Nano.Runtime.ISystemClock>();
                var apiInfo = HttpContextAccessor.HttpContext.RequestServices.GetService<IApiInfo>();
                var log = new AuditMessage
                {
                    TenantId = session.TenantId?.ToString() ?? string.Empty,
                    UserId = session.UserId?.ToString() ?? string.Empty,
                    UserFullName = session.UserFullName ?? string.Empty,
                    Event = auditEvent.EventType,
                    Data = auditEvent.ToJson(),
                    AuditTime = systemClock.UtcNow.ToUnixTimeSeconds(),
                    EventId = apiEvent.Action.TraceId,
                    ApiName = apiInfo.Name,
                    Status = apiEvent.Action.ResponseStatusCode,
                    Url = apiEvent.Action.RequestUrl
                };

                return log;
            }
            throw new K9Exception("WebApiAuditDataProvider should only be used to store AuditEventWebApi.");
        }

        public override object InsertEvent(AuditEvent auditEvent)
        {
            try
            {
                var log = MapToMessage(auditEvent);
                _client.Audit(log);
                return null;
            }
            catch (System.Exception ex)
            {
                _logger.LogError(ex, "Failed to save audit log");
                return null;
            }
        }
    }
}